(SST) ShlWAPI.pas Version 1.08

Developer Reference
(SST)ShlWAPI SHUnicodeToAnsi Function
Converts the characters of a Unicode string into ANSI characters and writes them into the provided buffer.
Scope
Global (i.e. this function can be called/accessed from code in any unit that includes/uses (SST)ShlWAPI.pas).
Syntax
function SHUnicodeToAnsi(pwszSrc : LPCWSTR; pszDst : LPSTR; cchBuf : Integer) : Integer;
Parameters
pwszSrc [in] The address of, or a pointer to, the zero-terminated, Unicode string to copy and convert.
pszDst [out] The address of, or a pointer to, the null-terminated buffer, into which the function should write the ANSI conversion of the input string.
cchBuf [in] Size, in number ANSI (i.e. single byte) characters, of the buffer specified in parameter pszDst.
Return Values
If the function succeeds, it returns the number of single byte characters (including the terminating null-character) it wrote into the the buffer specified in pszDst. If the function fails for any reason, it returns zero (0).
Remarks
The function always terminates the output string it writes into the provided buffer with a ANSI (i.e. single byte) null-character, even if the buffer is only large enough to accomodate the terminating, null-character itself (i.e the buffer has a size of 1 byte).
Even if the function only writes the terminating, ANSI, null-character into the buffer (i.e. the buffer is only large enough to accomodate a single byte/character) the return value represents the exact number of characters written to the ouput buffer, which in this case it would be 1 (see example output below).
Contrary to the Microsoft documentation accomponying MS SDK 6.1, if the converted output string is truncated, typically because the output buffer is not large enough, this fact and the number of converted or omitted characters, can be easily determined by subtracting the value returned by the function from the length (including the terminating null character) of the Unicode input string. However, this feature can, but should not be used to determine the required output buffer size (see next, two remarks, below).
Unlike many other Windows, API functions, SHUnicodeToAnsi does not return the required buffer size if zero (0) is specified in the cchBuf parameter, nor if an invalid (e.g. NIL) pointer is passed to the function in pszDst. However, calling the Windows API GetLastError() after having called the function with an inadequate buffer size that is larger than zero (i.e. sizeof(buffer) > 0) typically returns Windows error code 122 (= ERROR_INSUFFICIENT_BUFFER), at least under Windows Vista with SP 1 and IE 8. But, this remains to be tested under other Windows and ShlWAPI.dll versions.
In the documentation accompanying MS SDK 6.1, Microsoft stresses, that calling the function with an insufficiently sized output buffer can compromise application security thru buffer overruns. The function should therefore not be called with an output bffer that cannot store the entire, converted string, including the terminating ANSI null-character. Specifying overlapping in- and output buffers (i.e. buffers that share the same memory range) should also be avoided.
The function is exported by name as of ShlWAPI.dll version 6.0 under Vista, but according to the declaration and documentation in MS SDK version 6.1, it is available as of ShlWAPI.dll 5.0, under Windows 2000. Unfortunately, an ordinal by which function can be accessed in versions pre-dating Vista was not documented. Nonetheless, we were able to determine that the function is exported by ordinal 217 down to and including Windows NT 4.0 with Internet Explorer 5.0 and 98 SE with Internet Explorer 5.0.
Example
PROCEDURE TForm4.TestShlWAPISHUnicodeToAnsi(Sender : TObject); //Support for function as ordinal 217 under Win 98 SE (with IE 5.0) confirmed !!! //Support for function as ordinal 217 under NT 4.0 with IE 5.0 confirmed !!! VAR srcwcharbuf : WideString; VAR srcstrlen : INTEGER; VAR destansibuf : ARRAY[0..64] OF CHAR; VAR destbufsize : INTEGER; VAR apiretval : INTEGER; VAR errorcode : INTEGER; VAR newinfoline : STRING; BEGIN srcwcharbuf := ''; srcstrlen := 0; FillChar(destansibuf, Length(destansibuf), #0); destbufsize := 0; apiretval := 0; errorcode := 0; //0 = NO_ERROR newinfoline := ''; srcwcharbuf := 'Hello Unicode to ANSI World !'; srcstrlen := Length(srcwcharbuf); destbufsize := Length(destansibuf); newinfoline := 'SHUnicodeToAnsi called with source string "' + srcwcharbuf + '" returned '; SetLastError(NO_ERROR); apiretval := SHUnicodeToAnsi(PWChar(srcwcharbuf), destansibuf, destbufsize); IF apiretval > 0 THEN newinfoline := newinfoline + IntToStr(apiretval) + ' dest buffer : "' + destansibuf + '"' ELSE BEGIN errorcode := INTEGER(GetLastError()); newinfoline := newinfoline + IntToStr(apiretval) + ' (the function call FAILED !), GetLastError returned : ' + IntToStr(errorcode); END; Memo1.Lines.Add(newinfoline); //Dest buffer length parameter set to 23 (too short by 6 character) FillChar(destansibuf, SizeOf(destansibuf), #0); destbufsize := 23; apiretval := 0; newinfoline := ''; errorcode := 0; newinfoline := 'SHUnicodeToAnsi called with source string "' + srcwcharbuf + '" (length: ' + IntToStr(srcstrlen) + ') returned : '; SetLastError(NO_ERROR); apiretval := SHUnicodeToAnsi(PWChar(srcwcharbuf), destansibuf, destbufsize); IF apiretval > 0 THEN BEGIN errorcode := INTEGER(GetLastError()); newinfoline := newinfoline + IntToStr(apiretval) + ' and in the dest buffer : "' + destansibuf + '"'; Memo1.Lines.Add(newinfoline); newinfoline := 'and GetLastError returned : ' + IntToStr(errorcode); END ELSE BEGIN errorcode := INTEGER(GetLastError()); newinfoline := newinfoline + IntToStr(apiretval) + ' (the function call FAILED !), GetLastError returned : ' + IntToStr(errorcode); END; Memo1.Lines.Add(newinfoline); //Dest buffer length parameter set to 2 (too short by 27 characters) FillChar(destansibuf, SizeOf(destansibuf), #0); destbufsize := 2; apiretval := 0; newinfoline := ''; errorcode := 0; newinfoline := 'SHUnicodeToAnsi called with source string "' + srcwcharbuf + '" (length: ' + IntToStr(srcstrlen) + ') returned : '; SetLastError(NO_ERROR); apiretval := SHUnicodeToAnsi(PWChar(srcwcharbuf), destansibuf, destbufsize); IF apiretval > 0 THEN BEGIN errorcode := INTEGER(GetLastError()); newinfoline := newinfoline + IntToStr(apiretval) + ' and in the dest buffer : "' + destansibuf + '"'; Memo1.Lines.Add(newinfoline); newinfoline := 'and GetLastError returned : ' + IntToStr(errorcode); END ELSE BEGIN errorcode := INTEGER(GetLastError()); newinfoline := newinfoline + IntToStr(apiretval) + ' (the function call FAILED !), GetLastError returned : ' + IntToStr(errorcode); END; Memo1.Lines.Add(newinfoline); //Dest buffer length parameter set to 1 (too short by 28 characters) FillChar(destansibuf, SizeOf(destansibuf), #0); destbufsize := 1; apiretval := 0; newinfoline := ''; errorcode := 0; newinfoline := 'SHUnicodeToAnsi called with source string "' + srcwcharbuf + '" (length: ' + IntToStr(srcstrlen) + ') returned : '; SetLastError(NO_ERROR); apiretval := SHUnicodeToAnsi(PWChar(srcwcharbuf), destansibuf, destbufsize); IF apiretval > 0 THEN BEGIN errorcode := INTEGER(GetLastError()); newinfoline := newinfoline + IntToStr(apiretval) + ' and in the dest buffer : "' + destansibuf + '"'; Memo1.Lines.Add(newinfoline); newinfoline := 'and GetLastError returned : ' + IntToStr(errorcode); END ELSE BEGIN errorcode := INTEGER(GetLastError()); newinfoline := newinfoline + IntToStr(apiretval) + ' (the function call FAILED !), GetLastError returned : ' + IntToStr(errorcode); END; Memo1.Lines.Add(newinfoline); //Dest buffer length parameter set to 0 FillChar(destansibuf, SizeOf(destansibuf), #0); destbufsize := 0; apiretval := 0; newinfoline := ''; errorcode := 0; newinfoline := 'SHUnicodeToAnsi called with source string "' + srcwcharbuf + '" (length: ' + IntToStr(srcstrlen) + ') returned : '; SetLastError(NO_ERROR); apiretval := SHUnicodeToAnsi(PWChar(srcwcharbuf), destansibuf, destbufsize); IF apiretval > 0 THEN BEGIN errorcode := INTEGER(GetLastError()); newinfoline := newinfoline + IntToStr(apiretval) + ' and in the dest buffer : "' + destansibuf + '"'; Memo1.Lines.Add(newinfoline); newinfoline := 'and GetLastError returned : ' + IntToStr(errorcode); END ELSE BEGIN errorcode := INTEGER(GetLastError()); newinfoline := newinfoline + IntToStr(apiretval) + ' (the function call FAILED !), GetLastError returned : ' + IntToStr(errorcode); END; Memo1.Lines.Add(newinfoline); //No dest buffer (pointer param set to NIL) //and buffer length parameter set to 0 FillChar(destansibuf, SizeOf(destansibuf), #0); destbufsize := 0; apiretval := 0; newinfoline := ''; errorcode := 0; newinfoline := 'SHUnicodeToAnsi called with source string "' + srcwcharbuf + '" (length: ' + IntToStr(srcstrlen) + ') returned : '; SetLastError(NO_ERROR); apiretval := SHUnicodeToAnsi(PWChar(srcwcharbuf), NIL, 0); IF apiretval > 0 THEN BEGIN errorcode := INTEGER(GetLastError()); newinfoline := newinfoline + IntToStr(apiretval) + ' and in the dest buffer : "' + destansibuf + '"'; Memo1.Lines.Add(newinfoline); newinfoline := 'and GetLastError returned : ' + IntToStr(errorcode); END ELSE BEGIN errorcode := INTEGER(GetLastError()); newinfoline := newinfoline + IntToStr(apiretval) + ' (the function call FAILED !), GetLastError returned : ' + IntToStr(errorcode); END; Memo1.Lines.Add(newinfoline); Memo1.Lines.Add(''); END;
When run under Windows Vista with SP 1 and IE 8, the above code produces the following results (note the error codes reurned by the Windows API function GetLastError when the function fails):
SHUnicodeToAnsi called with source string "Hello Unicode to ANSI World !" returned 30 dest buffer : "Hello Unicode to ANSI World !" SHUnicodeToAnsi called with source string "Hello Unicode to ANSI World !" (length: 29) returned : 23 and in the dest buffer : "Hello Unicode to ANSI " and GetLastError returned : 122 SHUnicodeToAnsi called with source string "Hello Unicode to ANSI World !" (length: 29) returned : 2 and in the dest buffer : "H" and GetLastError returned : 122 SHUnicodeToAnsi called with source string "Hello Unicode to ANSI World !" (length: 29) returned : 1 and in the dest buffer : "" and GetLastError returned : 122 SHUnicodeToAnsi called with source string "Hello Unicode to ANSI World !" (length: 29) returned : 0 (the function call FAILED !), GetLastError returned : 0 SHUnicodeToAnsi called with source string "Hello Unicode to ANSI World !" (length: 29) returned : 0 (the function call FAILED !), GetLastError returned : 0
Requirements
Unit: Declared and imported in (SST)ShlWAPI.pas
Library: (SST)ShlWAPI.dcu/(SST)ShlWAPI.obj
Unicode: Not applicable.
Min. ShlWAPI.dll version according to MS SDK doc.: 5.0
Min. ShlWAPI.dll version based on SST research: 5.0
Min. OS version(s) according to Microsoft SDK doc.: Windows 2000, Windows 2000 Server, Windows Server 2003, Windows XP
Min. OS version(s) according to SST research.: Windows NT 4.0 with IE 5, Windows 98 SE with IE 5, Windows 2000, Windows XP, Windows Server 2003.
See Also
SHUnicodeToAnsi, SHAnsiToAnsi, SHUnicodeToUnicode.
 
Windows APIs: SHUnicodeToAnsi, SHAnsiToUnicode, SHUnicodeToUnicode SHAnsiToAnsi.


Document/Contents version 1.00
Page/URI last updated on 07.12.2023
 
Copyright © Stoelzel Software Technologie (SST) 2010 - 2015
Suggestions and comments mail to:
webmaster@stoelzelsoftwaretech.com